package com.example.common.grpc;

import com.example.common.constants.ServiceNames;
import com.example.game.proto.internal.*;
import io.grpc.Status;
import lombok.extern.slf4j.Slf4j;


/**
 * @author: Allen
 * @create: 2025/7/3 16:38
 * @description:
 **/
@Slf4j
public abstract class GrpcClientBase {


    public GrpcClientManager clientManager;

    public GrpcClientBase(GrpcClientManager clientManager) {
        this.clientManager = clientManager;
    }

    /**
     * 向指定服务发送心跳
     */
    public void sendHeartbeatToService(ServiceNames serviceType) {
        try {
            int currentServerId = clientManager.getCurrentServerId();

            // 创建心跳请求
            SrvReq heartbeatReq = SrvReq.newBuilder()
                    .setSid(currentServerId)
                    .build();

            // 使用专门的heartbeat方法
            long start = System.currentTimeMillis();
            SrvResp response = clientManager.callHeartbeat(serviceType, heartbeatReq);
            long end = System.currentTimeMillis() -start;
            log.debug("心跳检测成功: {} -> 服务器ID: {}, 响应: {}ms",
                    serviceType, currentServerId, end);
        } catch (Exception e) {
            log.error("心跳检测失败: {}", serviceType);
        }
    }

    /**
     * 异步向指定服务发送心跳
     */
    public void sendHeartbeatToServiceAsync(ServiceNames serviceType) {
        try {
            int currentServerId = clientManager.getCurrentServerId();

            // 创建心跳请求
            SrvReq heartbeatReq = SrvReq.newBuilder()
                    .setSid(currentServerId)
                    .build();

            // 使用专门的异步heartbeat方法
            clientManager.callHeartbeatAsync(serviceType, heartbeatReq, new DefaultResponseObserverResp());

            log.debug("异步心跳检测发送: {} -> 服务器ID: {}", serviceType, currentServerId);
        } catch (Exception e) {
            log.error("异步心跳检测失败: {}", serviceType, e);
        }
    }


    /**
     * 发送消息到Lobby服务
     *
     * @param code 协议号
     * @param userId 用户ID
     * @param data 消息数据
     * @return 响应消息
     */
    public SrvResp sendMessageToGate(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("发送消息到Lobby服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            SrvResp response = clientManager.callService(ServiceNames.LOBBY, request);
            log.debug("收到Lobby服务响应: id={}, ret={}, serverId={}", response.getId(), response.getRet(), response.getSid());

            return response;
        } catch (Exception e) {
            log.error("发送消息到Lobby服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("发送消息到Lobby服务失败", e);
        }
    }

    /**
     * 异步发送消息到Gate服务
     */
    public void sendMessageToGateAsync(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("异步发送消息到Gate服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            clientManager.callServiceAsync(ServiceNames.GATE, request, new DefaultResponseObserverResp());
        } catch (Exception e) {
            log.error("异步发送消息到Gate服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("异步发送消息到Gate服务失败", e);
        }
    }


    /**
     * 发送消息到Lobby服务
     *
     * @param code 协议号
     * @param userId 用户ID
     * @param data 消息数据
     * @return 响应消息
     */
    public SrvResp sendMessageToLobby(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("发送消息到Lobby服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            SrvResp response = clientManager.callService(ServiceNames.LOBBY, request);
            log.debug("收到Lobby服务响应: id={}, ret={}, serverId={}", response.getId(), response.getRet(), response.getSid());

            return response;
        } catch (Exception e) {
            log.error("发送消息到Lobby服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("发送消息到Lobby服务失败", e);
        }
    }

    /**
     * 异步发送消息到Lobby服务
     */
    public void sendMessageToLobbyAsync(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("异步发送消息到Lobby服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            clientManager.callServiceAsync(ServiceNames.LOBBY, request, new DefaultResponseObserverResp());
        } catch (Exception e) {
            log.error("异步发送消息到Lobby服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("异步发送消息到Lobby服务失败", e);
        }
    }

    /**
     * 发送消息到Game服务
     *
     * @param code 协议号
     * @param userId 用户ID
     * @param data 消息数据
     * @return 响应消息
     */
    public SrvResp sendMessageToGame(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("发送消息到Game服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            SrvResp response = clientManager.callService(ServiceNames.GAME, request);
            log.debug("收到Game服务响应: id={}, ret={}, serverId={}", response.getId(), response.getRet(), response.getSid());

            return response;
        } catch (Exception e) {
            log.error("发送消息到Game服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("发送消息到Game服务失败", e);
        }
    }

    /**
     * 异步发送消息到Game服务
     */
    public void sendMessageToGameAsync(int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("异步发送消息到Game服务: code={}, userId={}, bodyLen={}", code, userId, data != null ? data.length : 0);

            clientManager.callServiceAsync(ServiceNames.GAME, request, new DefaultResponseObserverResp());
        } catch (Exception e) {
            log.error("异步发送消息到Game服务失败: code={}, userId={}", code, userId, e);
            throw new RuntimeException("异步发送消息到Game服务失败", e);
        }
    }

    /**
     * 调用指定服务器ID的服务
     */
    public SrvResp callServiceByServerId(int targetServerId, int code, int userId, byte[] data) {
        try {
            int currentServerId = clientManager.getCurrentServerId();
            SrvReq request = GrpcMessageBuilder.buildSrvReq(currentServerId, code, userId, data);
            log.info("调用指定服务器: targetServerId={}, code={}, userId={}", targetServerId, code, userId);

            SrvResp response = clientManager.callServiceByServerId(targetServerId, request);
            log.debug("收到指定服务器响应: id={}, ret={}, serverId={}", response.getId(), response.getRet(), response.getSid());

            return response;
        } catch (Exception e) {
            log.error("调用指定服务器失败: targetServerId={}, code={}, userId={}", targetServerId, code, userId, e);
            throw new RuntimeException("调用指定服务器失败: " + targetServerId, e);
        }
    }

    /**
     * 统一处理gRPC异常，识别服务下线情况
     */
    public void handleGrpcException(String operation, Exception e, String context) {
        String errorMessage = e.getMessage();

        // 检查是否为服务不可用相关的异常
        if (e instanceof io.grpc.StatusRuntimeException) {
            io.grpc.StatusRuntimeException grpcException = (io.grpc.StatusRuntimeException) e;
            Status status = grpcException.getStatus();

            switch (status.getCode()) {
                case UNAVAILABLE:
                    log.error("🚨 {}失败 - {}可能已下线: context={}, status={}",
                            operation, ServiceNames.GAME.value(), context, status.getDescription());
                    break;
                case NOT_FOUND:
                    log.error("🚨 {}失败 - {}实例未找到: context={}, status={}",
                            operation, ServiceNames.GAME.value(), context, status.getDescription());
                    break;
                case DEADLINE_EXCEEDED:
                    log.error("🚨 {}失败 - {}响应超时: context={}, status={}",
                            operation, ServiceNames.GAME.value(), context, status.getDescription());
                    break;
                default:
                    log.error("🚨 {}失败 - {}调用异常: context={}, status={}, error={}",
                            operation, ServiceNames.GAME.value(), context, status.getCode(), errorMessage, e);
            }
        } else {
            // 其他类型的异常
            if (errorMessage != null && (errorMessage.contains("UNAVAILABLE") ||
                    errorMessage.contains("NOT_FOUND") ||
                    errorMessage.contains("Connection refused"))) {
                log.error("🚨 {}失败 - {}可能已下线: context={}, error={}",
                        operation, ServiceNames.GAME.value(), context, errorMessage);
            } else {
                log.error("🚨 {}失败 - {}调用异常: context={}, error={}",
                        operation, ServiceNames.GAME.value(), context, errorMessage, e);
            }
        }
    }

}
